package edu.uow.scsse.main.metrics;

import java.awt.event.ActionEvent;
import java.util.List;

import javax.swing.JOptionPane;

//import org.apache.log4j.Logger;

import edu.uow.scsse.main.domain.Edge;
import edu.uow.scsse.main.domain.EdgeType;
import edu.uow.scsse.main.domain.Graph;
import edu.uow.scsse.main.domain.Node;
import edu.uow.scsse.main.domain.NodeType;

/**
 * Design Metrics Calculation
 * @author Tiancheng Zhang
 *
 */
public class DesignMetricsCalculation {

	
//	private static final Logger logger = Logger.getLogger(DesignMetricsCalculation.class);
	/**Trigging Event Domain Graph List*/
	private List<Graph> trDomainGraphList;
	private double sumTEAlt;
	private double sumSubAlt;
	private double sumTEAction;
	private double sumSubAction;
	private static double sumForManualWeight;
	private static int count;
	
	
	/**
	 * Constructor
	 * @param trDomainGraphList
	 */
	public DesignMetricsCalculation(List<Graph> trDomainGraphList)
	{
		this.trDomainGraphList = trDomainGraphList;
		sumTEAlt = 0;
		sumSubAlt = 0;
		sumTEAction = 0;
		sumSubAction = 0;
	}
	
	/**
	 *Reset for next time usage
	 *@param trDomainGraphList
	 */
	public void resetAllVariables(List<Graph> trDomainGraphList)
	{
		this.trDomainGraphList = trDomainGraphList;
		sumTEAlt = 0;
		sumSubAlt = 0;
		sumTEAction = 0;
		sumSubAction = 0;
	}
	
	/**
	 * reactiveness Calculation
	 * @return reactiveness design metrics
	 */
	public double reactivnessCalculation(boolean defaultBeliefWeight, double defaultTEAltWeight, String agentName)
	{
		if(trDomainGraphList.size() == 0)
			return 0;
		
		double sum = 0;
//		double alpha = 1.0/trDomainGraphList.size();
		double alpha = 1.0;
		double accualpha = 0;
		
		for(Graph eachGraph: trDomainGraphList)
		{
			sumTEAlt = 0;
			sumSubAlt = 0;
			sumTEAction = 1;
			sumSubAction = 1;
			if(eachGraph.getNodes().size() == 0)
				continue;
				
			DFSAltPlanPriorityCalculation(eachGraph, -1, NodeType.TRIGGINGEVENT);
			//manually
			if(!defaultBeliefWeight)
			{
				boolean flag = true;
				do
				{
					String result = JOptionPane.showInputDialog("Enter Weight For Trigging Event " + eachGraph.getNodes().get(0).getName() + " in agent:"+agentName+" :");
					try{
						alpha = Double.parseDouble(result);
//						if(accualpha + alpha > 1)
//						{
//							JOptionPane.showMessageDialog(null, "Weight should between 0 and "+ (1-accualpha)+", please try agaign!");
//							flag = false;
//						}
//						else
//						{	
//							flag = true;
//						}
						flag = true;
					}catch(Exception e)
					{
						JOptionPane.showMessageDialog(null, "Invalid Weight, try again!");
						flag = false;
					}
				}while(flag ==false);
				accualpha += alpha;
			}
			sum += alpha*((sumTEAction == 0)? 0 : ((defaultTEAltWeight)*sumTEAlt)/(double)sumTEAction + (sumSubAction == 0? 0: ((1 - defaultTEAltWeight)*sumSubAlt)/(double)sumSubAction));
		}
		return sum;

			
	}
	
	
	

	/**
	 *Calculate reactiveness for each domain of triggering event based on Alternative plan priority DFS
	 *@param domainGraph
	 *@param currentNode
	 */
	private void DFSAltPlanPriorityCalculation(Graph domainGraph, int currentNodeId, NodeType domainType)
	{
//		logger.info("Visited Nodes : " + numOfVisitedNodes(domainGraph) + " Total Nodes: " + domainGraph.getNodes().size());
		if(numOfVisitedNodes(domainGraph) != domainGraph.getNodes().size())
		{
			Node currentNode = domainGraph.findNodeById(currentNodeId);
//			logger.info("Processing Node: " + (currentNode != null? currentNode.getName():"null"));
			//not visited
			if(currentNode != null && !currentNode.getVisitedFlag())
			{
				/*if(currentNode.getType().equals(NodeType.SUBGOAL))
				{
					sumNumerator++;
				}
				else */
				//subgoal with context condition with action or subgoal
				if(domainType.equals(NodeType.SUBGOAL)&&currentNode.getType().equals(NodeType.CONTEXT_CONDITION) && currentNode.getOutgoingEdges().size() == 1 
						&& (domainGraph.findNodeById(currentNode.getOutgoingEdges().get(0).getDestinationId()).getType().equals(NodeType.ACTION)
						||domainGraph.findNodeById(currentNode.getOutgoingEdges().get(0).getDestinationId()).getType().equals(NodeType.SUBGOAL)))
				{
					//increment valid subgoal
					this.sumSubAlt++;
				}
				//triggering event alternative plan not necessary with context condition
				else if(domainType.equals(NodeType.TRIGGINGEVENT)&&currentNode.getType().equals(NodeType.PLAN))
				{
					this.sumTEAlt++;
				}
				else if(currentNode.getType().equals(NodeType.ACTION))
				{
					if(domainType.equals(NodeType.SUBGOAL))
					{
						this.sumSubAction++;
					}
					else if(domainType.equals(NodeType.TRIGGINGEVENT))
					{
						this.sumTEAction++;
					}
						
				}
				//set to visited
				domainGraph.findNodeById(currentNodeId).setVisitedFlag(true);
//				logger.info("Set Node: " + (currentNode != null? currentNode.getName():"null") + "->VISITED");
				//alternative plan priority
				if(currentNode.getType().equals(NodeType.SUBGOAL) || currentNode.getType().equals(NodeType.TRIGGINGEVENT))
				{
					for(Edge eachEdge: currentNode.getOutgoingEdges())
					{
//						logger.info("Has Outgoing Edge Pointing to " + domainGraph.findNodeById(eachEdge.getDestinationId()).getName());
						//if the subgoal has alternative plan and the node being linked is not visited
						if(eachEdge.getType().equals(EdgeType.ALTPLANEDGE) && !(domainGraph.findNodeById(eachEdge.getDestinationId())).getVisitedFlag())
						{
							DFSAltPlanPriorityCalculation(domainGraph, eachEdge.getDestinationId(), currentNode.getType());
						}
					}
				}
				
				//DFS other nodes
				for(Edge eachEdge: currentNode.getOutgoingEdges())
				{
//					logger.info("Has Outgoing Edge Pointing to " + domainGraph.findNodeById(eachEdge.getDestinationId()).getName());
					//if the subgoal has alternative plan and the node being linked is not visited
					if(eachEdge.getType().equals(EdgeType.SEQUENCIALEDGE) && !(domainGraph.findNodeById(eachEdge.getDestinationId())).getVisitedFlag())
					{
						DFSAltPlanPriorityCalculation(domainGraph, eachEdge.getDestinationId(), domainType);
					}
				}
				
			}
		}
		else
			return;
	}
	
	/**
	 * Number of visited Node
	 * @param domainGraph
	 * @return visitedNode
	 */
	private int numOfVisitedNodes(Graph domainGraph)
	{
		int nodesVisited = 0;
		for(Node eachNode: domainGraph.getNodes())
		{
			if(eachNode.getVisitedFlag() == true)
				nodesVisited++;
		}
		return nodesVisited;
	}
	
	
}
